{{define "theme-default/home"}}
{{template "theme-default/header" .}}

<script>
    // 添加服务器数量徽章样式
    const style = document.createElement('style');
    style.textContent = `
        .custom-tab {
            position: relative;
            display: inline-block;
        }
        
        .server-count-badge {
            position: absolute;
            top: 5px;
            right: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            background-color: #03a9f4;
            color: white;
            border-radius: 50%;
            width: 14px;
            height: 14px;
            font-size: 8px;
            font-weight: bold;
            line-height: 1;
            min-width: 14px;
            z-index: 1;
            /* 默认未选中时降低不透明度 */
            opacity: 0.8;
            transition: opacity 0.2s ease;
        }
        
        .custom-tab[data-tag="online"] .server-count-badge {
            background-color: #4caf50;
        }
        
        .custom-tab[data-tag="offline"] .server-count-badge {
            background-color: #f44336;
        }
        
        .custom-tab.active .server-count-badge {
            /* 选中时显示原色（不降不透明度） */
            opacity: 1;
        }
        
        .custom-tab:hover .server-count-badge {
            /* 悬停时显示原色（不降不透明度） */
            opacity: 1;
        }
    `;
    document.head.appendChild(style);

    // 性能优化 - 覆盖默认事件监听器为被动模式
    (function () {
        // 保存原始的 addEventListener
        const originalAddEventListener = EventTarget.prototype.addEventListener;

        // 需要设置为被动的事件类型
        const passiveEvents = ['touchstart', 'touchmove', 'wheel', 'mousewheel'];

        // 重写 addEventListener
        EventTarget.prototype.addEventListener = function (type, listener, options) {
            if (passiveEvents.includes(type) && typeof options !== 'object') {
                options = { passive: true };
            } else if (passiveEvents.includes(type) && typeof options === 'object' && options.passive === undefined) {
                options.passive = true;
            }

            return originalAddEventListener.call(this, type, listener, options);
        };
    })();
    // jQuery 事件优化 - 延迟到jQuery加载完成后执行
    document.addEventListener('DOMContentLoaded', function () {
        // 等待jQuery加载完成
        function waitForJQuery() {
            if (typeof $ !== 'undefined' && $.fn && $.fn.on) {
                const originalOn = $.fn.on;
                $.fn.on = function (events, selector, data, handler) {
                    if (typeof events === 'string' &&
                        (events.includes('touchstart') || events.includes('touchmove') ||
                            events.includes('wheel') || events.includes('mousewheel'))) {

                        const passiveHandler = function (e) {
                            if (typeof handler === 'function') {
                                return handler.call(this, e);
                            } else if (typeof data === 'function') {
                                return data.call(this, e);
                            }
                        };

                        if (typeof data === 'function') {
                            handler = data;
                            data = undefined;
                        }

                        this.each(function () {
                            if (this.addEventListener) {
                                this.addEventListener(events, passiveHandler, { passive: true });
                            }
                        });

                        return this;
                    }

                    return originalOn.apply(this, arguments);
                };
            } else {
                // jQuery还没加载完成，100ms后重试
                setTimeout(waitForJQuery, 100);
            }
        }

        waitForJQuery();
    });
</script>

{{if ts .CustomCode}} {{.CustomCode|safe}} {{end}}
{{template "theme-default/menu" .}}

<div class="nb-container">
    <div class="ui container" style="padding-bottom: 30px;">
        <div class="tabs-wrapper">
            <div v-if="servers && servers.length > 0" class="custom-tabs-container" ref="tabsContainer">
                <div class="tabs-content-area">
                    <div class="custom-tab" :class="{ active: activeTag === '' }" @click="handleTabClick('', $event)"
                        ref="allTab" data-tag="all">
                        {{tr "All"}}
                        <span class="server-count-badge" :style="getBadgeStyle('')">@#getServerCountForTag('')#@</span>
                    </div>
                    <div class="custom-tab" :class="{ active: activeTag === 'online' }"
                        @click="handleTabClick('online', $event)" ref="onlineTab" data-tag="online">
                        {{tr "OnlineServers"}}
                        <span class="server-count-badge" :style="getBadgeStyle('online')">@#getServerCountForTag('online')#@</span>
                    </div>
                    <div class="custom-tab" :class="{ active: activeTag === 'offline' }"
                        @click="handleTabClick('offline', $event)" ref="offlineTab" data-tag="offline">
                        {{tr "OfflineServers"}}
                        <span class="server-count-badge" :style="getBadgeStyle('offline')">@#getServerCountForTag('offline')#@</span>
                    </div>
                    <div v-for="(tag, index) in uniqueTags.slice().reverse()" :key="tag" class="custom-tab"
                        :class="{ active: activeTag === tag }" @click="handleTabClick(tag, $event)"
                        :ref="'tagTab' + index" data-tag="custom">
                        @#tag#@
                        <span class="server-count-badge" :style="getBadgeStyle(tag)">@#getServerCountForTag(tag)#@</span>
                    </div>
                </div>
                <div class="tab-slider" ref="tabSlider"></div>
            </div>
        </div>

        <template v-if="filteredServers && filteredServers.length > 0">
            <div class="ui four stackable status cards">
                <div v-for="server in filteredServers" :key="server.ID" :id="server.ID" class="ui card">
                    <div class="content" v-if="server.Host" style="padding-bottom: 5px">
                        <div class="header">
                            <i :class="'fi fi-'+server.Host.CountryCode"></i>
                            <i v-if='isWindowsPlatform(server.Host.Platform)' class="windows icon"></i>
                            <i v-else-if='getFontLogoClass(server.Host.Platform) == "" && server.State.Uptime > 0'
                                class="fl-tux"></i>
                            <i v-else :class="'fl-' + getFontLogoClass(server.Host.Platform)"></i>
                            @#server.Name + (server.live?'':' [{{tr "Offline"}}]')#@
                            <i class="server-primary-font info circle icon" style="height: 28px" data-server-popup></i>
                            <div class="server-popup-content" style="display: none;">
                                {{tr "Platform"}}：@#specialOS(server.Host.Platform)#@ <span
                                    v-if='!isWindowsPlatform(server.Host.Platform)'>@#formatPlatformVersion(server.Host.PlatformVersion)#@
                                </span> @#specialVir(server.Host.Virtualization)#@
                                [@#server.Host.Arch#@]<br />
                                {{tr "MemUsed"}}：@#formatByteSize(server.State.MemUsed)#@ /
                                @#formatByteSize(server.Host.MemTotal)#@<br />
                                <template v-if="server.Host.SwapTotal">
                                    {{tr "SwapUsed"}}：@#formatByteSize(server.State.SwapUsed)#@ /
                                    @#formatByteSize(server.Host.SwapTotal)#@<br />
                                </template>
                                {{tr "DiskUsed"}}：@#formatByteSize(server.State.DiskUsed)#@ /
                                @#formatByteSize(server.Host.DiskTotal)#@<br />
                                <template v-if="getTrafficTooltip(server.ID)">
                                    {{tr "TrafficTotal"}}：@#getTrafficTooltip(server.ID)#@<br />
                                </template>
                                <template
                                    v-if="server.Host.GPU && server.Host.GPU.length > 0 && server.Host.GPU.some(gpu => gpu !== 'unknown')">
                                    {{tr "GPU"}}：@#server.Host.GPU.filter(gpu => gpu !== 'unknown').join(', ')#@<br />
                                </template>
                                <template v-if="hasTemperature(server.State.Temperatures, sensorList)">
                                    {{tr "Temperature"}}：@#getTemperature(server.State.Temperatures,
                                    sensorList)#@°C<br />
                                </template>

                                {{tr "Load"}}：@#toFixed2(server.State.Load1)#@ | @#toFixed2(server.State.Load5)#@ |
                                @#toFixed2(server.State.Load15)#@<br />
                                {{tr "ConnCount"}}：TCP @#server.State.TcpConnCount#@ {{tr "Count"}} | UDP
                                @#server.State.UdpConnCount#@ {{tr "Count"}}
                                <br />
                                {{tr "BootTime"}}：@#timeStamp(server.Host.BootTime * 1000)#@<br />
                                {{tr "LastActive"}}：@#timeStamp(server.LastActive)#@<br />
                                {{tr "Version"}}：@#server.Host.Version#@<br />
                            </div>
                            <div class="ui divider"
                                style="margin: .5rem 0 !important; border-bottom: 1px solid rgba(34,36,38,.15) !important;">
                            </div>
                        </div>

                        <div class="header header_info">
                            <i class="fa-solid fa-microchip"></i>
                            <div class="cpuroll" style="white-space: nowrap;overflow: hidden;">
                                <div class="cpucontent rollanimation">
                                    @#clearString(server.Host.CPU).join(" ")#@
                                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                                </div>
                                <div class="cpucontent rollanimation">
                                    @#clearString(server.Host.CPU).join(" ")#@
                                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
                                </div>
                            </div>
                            <div style="display: flex; align-items: center;">
                                <i class="fa-solid fa-memory"></i>
                                @#getK2Gb(server.Host.MemTotal)#@
                                <span>&nbsp;&nbsp;</span>
                                <i class="fa-solid fa-hard-drive"></i>
                                @#getK2Gb(server.Host.DiskTotal)#@
                            </div>
                        </div>

                        <div class="description">
                            <div class="ui grid">
                                <div class="three wide column">CPU</div>
                                <div class="thirteen wide column">
                                    <div :class="formatPercent(server.live,server.State.CPU, 100).class">
                                        <div class="bar"
                                            :style="formatPercent(server.live,server.State.CPU, 100).style">
                                            <small>@#formatPercent(server.live,server.State.CPU,100).percent#@%</small>
                                        </div>
                                    </div>
                                </div>
                                <div class="three wide column">{{tr "MemUsed"}}</div>
                                <div class="thirteen wide column">
                                    <div
                                        :class="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).class">
                                        <div class="bar"
                                            :style="formatPercent(server.live,server.State.MemUsed, server.Host.MemTotal).style">
                                            <small>@#parseInt(server.State&&server.Host.MemTotal?server.State.MemUsed/server.Host.MemTotal*100:0)#@%</small>
                                        </div>
                                    </div>
                                </div>
                                <div class="three wide column">{{tr "DiskUsed"}}</div>
                                <div class="thirteen wide column">
                                    <div
                                        :class="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).class">
                                        <div class="bar"
                                            :style="formatPercent(server.live,server.State.DiskUsed, server.Host.DiskTotal).style">
                                            <small>@#parseInt(server.State&&server.Host.DiskTotal?server.State.DiskUsed/server.Host.DiskTotal*100:0)#@%</small>
                                        </div>
                                    </div>
                                </div>

                                <div class="three wide column">{{tr "TrafficTotal"}}</div>
                                <div class="thirteen wide column">
                                    <div :class="getTrafficProgressClass(server.ID)">
                                        <div class="bar" :style="getTrafficProgressStyle(server.ID)">
                                            <small>@#getTrafficDisplay(server.ID)#@</small>
                                        </div>
                                    </div>
                                </div>

                                <div class="three wide column">{{tr "NetSpeed"}}</div>
                                <div class="thirteen wide column">
                                    <i class="fa-regular fa-down"></i>
                                    @#formatByteSize(server.State.NetInSpeed)#@/s |
                                    <i class="fa-regular fa-up"></i>
                                    @#formatByteSize(server.State.NetOutSpeed)#@/s
                                </div>
                                <div class="three wide column">{{tr "NetTransfer"}}</div>
                                <div class="thirteen wide column">
                                    <i class="fa-solid fa-down"></i>
                                    @#formatByteSize(server.State.NetInTransfer)#@ |
                                    <i class="fa-solid fa-up"></i>
                                    @#formatByteSize(server.State.NetOutTransfer)#@
                                </div>
                                
                                <div class="three wide column">{{tr "Live"}}</div>
                                <div class="thirteen wide column"><i class="fa-regular fa-bars-progress"></i>
                                    @# server.State.ProcessCount #@ | <i class="fa-sharp fa-solid fa-t"></i>
                                    @#server.State.TcpConnCount#@ |
                                    <i class="fa-sharp fa-solid fa-u"></i>
                                    @#server.State.UdpConnCount#@
                                </div>
                                
                                <div class="three wide column">{{tr "Uptime"}}</div>
                                <div class="thirteen wide column">
                                <i class="clock icon"></i>@#secondToDate(server.State.Uptime)#@
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="content" v-else>
                        <p>@#server.Name#@</p>
                        <p><i class="fas fa-circle-notch fa-spin"></i> {{tr "Connecting"}}...</p>
                    </div>
                </div>
            </div>
        </template>
        <template v-else-if="servers && servers.length > 0 && filteredServers.length === 0 && activeTag !== ''">
            <div class="ui message info">
                <div class="header">
                    <span v-if="activeTag === 'online'">{{tr "NoOnlineServers"}}</span>
                    <span v-else-if="activeTag === 'offline'">{{tr "NoOfflineServers"}}</span>
                    <span v-else>{{tr "NoServersForTagH"}} "@#activeTag#@"</span>
                </div>
                <p>
                    <span v-if="activeTag === 'online'">{{tr "NoOnlineServersDesc"}}</span>
                    <span v-else-if="activeTag === 'offline'">{{tr "NoOfflineServersDesc"}}</span>
                    <span v-else>{{tr "NoServersForTagP"}}</span>
                </p>
            </div>
        </template>
        <template v-else>
            <div class="ui message info">
                <div class="header">
                    {{tr "NoServers"}}
                </div>
                <p>{{tr "NoServersDesc"}}</p>
            </div>
        </template>
    </div>
</div>

<!-- 隐藏的数据容器 -->
<div id="traffic-data" style="display: none;">{{.TrafficData}}</div>

{{template "common/footer" .}}

<script>
    // 确保流量提取函数可用
    window.trafficFunctionsReady = true;
    window.serverTrafficData = window.serverTrafficData || {};
    window.lastTrafficUpdateTime = window.lastTrafficUpdateTime || 0;

    // 提取流量数据的函数
    window.extractTrafficData = function () {
        try {
            const trafficDataElement = document.getElementById('traffic-data');
            let trafficItems = [];
            if (trafficDataElement && trafficDataElement.textContent) {
                try {
                    trafficItems = JSON.parse(trafficDataElement.textContent);
                } catch (e) {
                    console.warn('DOM数据解析失败:', e);
                }
            }
            if (!trafficItems || trafficItems.length === 0) {
                trafficItems = window.serverTrafficRawData || [];
            }
            if (!trafficItems || trafficItems.length === 0) return;

            const newTrafficData = {};
            trafficItems.forEach(item => {
                if (item && item.server_id) {
                    const serverId = String(item.server_id);
                    const serverName = item.server_name || "Unknown Server";

                    // 优先使用字节数据作为源数据
                    let maxBytes, usedBytes, percent;

                    if (item.is_bytes_source && typeof item.used_bytes === 'number' && typeof item.max_bytes === 'number') {
                        // 后端提供了字节数据源，直接使用
                        maxBytes = item.max_bytes;
                        usedBytes = item.used_bytes;

                        // 从字节数据计算百分比
                        if (maxBytes > 0) {
                            percent = (usedBytes / maxBytes) * 100;
                            percent = Math.max(0, Math.min(100, percent)); // 限制在0-100范围
                        } else {
                            percent = 0;
                        }
                    } else {
                        // 回退到解析格式化字符串
                        const maxTraffic = item.max_formatted || "0B";
                        const usedTraffic = item.used_formatted || "0B";

                        maxBytes = (typeof window.parseTrafficToBytes === 'function') ? window.parseTrafficToBytes(maxTraffic) : 0;
                        usedBytes = (typeof window.parseTrafficToBytes === 'function') ? window.parseTrafficToBytes(usedTraffic) : 0;

                        // 如果有后端计算的百分比，作为备选
                        if (typeof item.used_percent === 'number') {
                            percent = item.used_percent;
                        } else if (maxBytes > 0) {
                            percent = (usedBytes / maxBytes) * 100;
                            percent = Math.max(0, Math.min(100, percent));
                        } else {
                            percent = 0;
                        }
                    }

                    // 格式化显示字符串，使用readableBytes函数
                    const standardMax = (typeof window.formatTrafficUnit === 'function') ?
                        window.formatTrafficUnit(readableBytes(maxBytes)) : readableBytes(maxBytes);
                    const standardUsed = (typeof window.formatTrafficUnit === 'function') ?
                        window.formatTrafficUnit(readableBytes(usedBytes)) : readableBytes(usedBytes);

                    newTrafficData[serverId] = {
                        max: standardMax,
                        used: standardUsed,
                        percent: Math.round(percent * 100) / 100,
                        maxBytes: maxBytes,
                        usedBytes: usedBytes,
                        serverName: serverName,
                        cycleName: item.cycle_name || "Unknown",
                        isBytesSource: item.is_bytes_source || false
                    };
                }
            });

            window.serverTrafficData = newTrafficData;
            window.lastTrafficUpdateTime = Date.now();

            if (window.statusCards && typeof window.statusCards.updateTrafficData === 'function') {
                window.statusCards.updateTrafficData();
            }
        } catch (e) {
            console.error('提取流量数据时出错:', e);
        }
    };

    // 立即提取数据
    setTimeout(window.extractTrafficData, 1000);

    // 定期更新
    setInterval(window.extractTrafficData, 30000);

    // Vue实例配置
    const statusCards = new Vue({
        el: '#app',
        delimiters: ['@#', '#@'],
        data: {
            page: 'index',
            defaultTemplate: '{{.Conf.Site.Theme}}',
            templates: {{.Themes }},
    servers: [],
        cache: [],
            activePopup: null,
                trafficData: { },
    _trafficVersion: 0,
        sensorList: [
            'TC0D',
            'TC0H',
            'TC0P',
            'k10temp',
            'k10temp_tctl',
            'coretemp_package_id_0',
            'cpu_thermal_zone',
            'cpu-thermal',
            'soc_thermal',
            'cpu_thermal',
            'ACPI\\ThermalZone\\TZ0__0',
            'ACPI\\ThermalZone\\CPUZ_0',
            'ACPI\\ThermalZone\\TZ00_0',
            'ACPI\\ThermalZone\\TZ001_0',
            'ACPI\\ThermalZone\\THM0_0'
        ],
            activeTag: '',
                uniqueTags: []
    },
    mixins: [mixinsVue],
        created() {
        try {
            const serverData = JSON.parse('{{.Servers}}');
            if (serverData && serverData.servers && Array.isArray(serverData.servers)) {
                this.servers = serverData.servers;
            } else {
                console.warn('服务器数据格式不正确，使用空数组');
                this.servers = [];
            }
        } catch (e) {
            console.error('解析服务器数据失败:', e);
            this.servers = [];
        }

        this.generateUniqueTags();
        // 初始化时设置所有服务器的初始状态
        this.servers.forEach(server => {
            if (server.Host) {
                // 初始化时先假设所有服务器在线，等待WebSocket更新
                server.live = true;
                server._offlineConfirmCount = 0;
            } else {
                server.live = false;
            }
        });

        // 订阅流量数据更新
        if (window.trafficManager) {
            window.trafficManager.subscribe((data, version) => {
                this.trafficData = data;
                this._trafficVersion = version;
                this.updateTrafficData();
            });
        }

        // 不再设置定期更新，WebSocket会实时推送数据
    },
    mounted() {
        this.$nextTick(() => {
            this.updateSliderPosition();
            $('.ui.accordion').accordion();
        });
    },
    computed: {
        filteredServers() {
            if (!this.servers || !Array.isArray(this.servers)) {
                return [];
            }

            const displayableServers = this.servers.filter(server => server.Host);

            if (this.activeTag === '') {
                return displayableServers;
            } else if (this.activeTag === 'online') {
                return displayableServers.filter(server => server.live === true);
            } else if (this.activeTag === 'offline') {
                return displayableServers.filter(server => server.live === false);
            }

            return displayableServers.filter(server => server.Tag === this.activeTag);
        }
    },
    methods: {
        // 返回某个分组下可展示的服务器列表
        getGroupServers(tag) {
            if (!this.servers || !Array.isArray(this.servers)) return [];
            const displayable = this.servers.filter(s => s.Host);
            if (tag === '') return displayable;
            if (tag === 'online') return displayable.filter(s => s.live === true);
            if (tag === 'offline') return displayable.filter(s => s.live === false);
            return displayable.filter(s => s.Tag === tag);
        },
        // 计算某分组徽章颜色：
        // - 组内全部离线：#f44336（红色）
        // - 组内存在离线（且不是全部离线）：#ff8840（橙色）
        // - 其他：保留默认（空，使用CSS原色）
        getBadgeStyle(tag) {
            const servers = this.getGroupServers(tag);
            const total = servers.length;
            if (total === 0) return {};
            const offlineCount = servers.filter(s => s.live === false).length;
            if (offlineCount === total) {
                return { backgroundColor: '#f44336' };
            }
                if (offlineCount === 0) {
                    // 全部在线：绿
                    return { backgroundColor: '#4caf50' };
                }
                if (offlineCount > 0) {
                    // 部分离线：橙
                    return { backgroundColor: '#ff8840' };
                }
            return {};
        },
        getServerTrafficData(serverId) {
            if (!serverId) return null;

            // 首先尝试从 trafficManager 获取数据
            if (window.trafficManager) {
                const trafficData = window.trafficManager.getServerTrafficData(serverId);
                if (trafficData) {
                    return trafficData;
                }
            }

            // 如果 trafficManager 没有数据，尝试从全局数据获取
            if (window.serverTrafficData) {
                const serverIdStr = String(serverId).trim();
                if (window.serverTrafficData[serverIdStr]) {
                    return window.serverTrafficData[serverIdStr];
                }

                // 尝试数字匹配
                const numericId = parseInt(serverIdStr);
                if (!isNaN(numericId)) {
                    const keys = Object.keys(window.serverTrafficData);
                    for (const key of keys) {
                        if (parseInt(key) === numericId) {
                            return window.serverTrafficData[key];
                        }
                    }
                }
            }

            return null;
        },
        formatPlatformVersion(version) {
            if (!version) return '';
            if (/^[\d.]+$/.test(version)) {
                return version;
            }
            let cleanVersion = version.split('/')[0];
            return cleanVersion.split(' ').map(word => {
                if (word.length > 0) {
                    return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
                }
                return word;
            }).join(' ');
        },
        toFixed2(f) {
            return f.toFixed(2);
        },
        isWindowsPlatform(str) {
            return str && typeof str === 'string' && str.includes('indows');
        },
        getFontLogoClass(str) {
            const validPlatforms = [
                "almalinux", "alpine", "aosc", "apple", "archlinux", "archlabs",
                "artix", "budgie", "centos", "coreos", "debian", "deepin",
                "devuan", "docker", "elementary", "fedora", "ferris", "flathub",
                "freebsd", "gentoo", "gnu-guix", "illumos", "kali-linux",
                "linuxmint", "mageia", "mandriva", "manjaro", "nixos",
                "openbsd", "opensuse", "pop-os", "raspberry-pi", "redhat",
                "rocky-linux", "sabayon", "slackware", "snappy", "solus",
                "tux", "ubuntu", "void", "zorin"
            ];

            if (validPlatforms.includes(str)) {
                return str;
            }
            if (str === 'darwin') {
                return 'apple';
            }
            if (['openwrt', 'linux'].includes(str)) {
                return 'tux';
            }
            if (str === 'amazon') {
                return 'redhat';
            }
            if (str === 'arch') {
                return 'archlinux';
            }
            if (str && typeof str === 'string' && str.toLowerCase().includes('opensuse')) {
                return 'opensuse';
            }
            return '';
        },
        formatPercent(live, used, total) {
            let u = parseFloat(used);
            let t = parseFloat(total);

            if (isNaN(u) || isNaN(t)) {
                live = false;
            }

            let percent;
            if (live && t > 0) {
                percent = parseInt((u / t) * 100);
                if (isNaN(percent) || percent < 0) percent = 0;
                if (percent > 100) percent = 100;
            } else if (live && t === 0 && u === 0) {
                percent = 0;
            } else {
                percent = -1;
            }

            if (!this.cache[percent]) {
                let displayPercentValue = percent;
                let classObject = { ui: true, progress: true };
                let styleObject = {
                    'transition-duration': '300ms', // 增加过渡时间，使变化更平滑
                    'transition-timing-function': 'ease-out',
                    'min-width': 'unset',
                    width: (percent >= 0 ? percent : 0) + '% !important',
                };

                if (percent < 0) {
                    styleObject['background-color'] = 'slategray';
                    classObject.offline = true;
                    displayPercentValue = 0;
                } else if (percent < 60) {
                    styleObject['background-color'] = 'rgb(76,175,80)';
                    classObject.fine = true;
                } else if (percent < 90) {
                    styleObject['background-color'] = '#ff9800';
                    classObject.warning = true;
                } else {
                    styleObject['background-color'] = '#f44336';
                    classObject.error = true;
                }
                this.cache[percent] = {
                    class: classObject,
                    style: styleObject,
                    percent: displayPercentValue,
                };
            }

            return this.cache[percent] || {
                class: { ui: true, progress: true, offline: true },
                style: { width: '0%', 'background-color': 'slategray' },
                percent: 0
            };
        },
        secondToDate(s) {
            var d = Math.floor(s / 3600 / 24);
            if (d > 0) {
                return d + " {{tr "Day"}}";
            }
            var h = Math.floor(s / 3600 % 24);
            var m = Math.floor(s / 60 % 60);
            var s = Math.floor(s % 60);
            return h + ":" + ("0" + m).slice(-2) + ":" + ("0" + s).slice(-2);
        },
        timeStamp(t) {
            return new Date(t).format('yyyy年MM月dd日 HH:mm:ss');
        },
        formatByteSize(bs) {
            const x = this.readableBytes(bs);
            return x != "NaN undefined" ? x : '0B';
        },
        readableBytes(bytes) {
            if (!bytes) {
                return '0B';
            }
            const i = Math.floor(Math.log(bytes) / Math.log(1024));
            const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
            const value = parseFloat((bytes / Math.pow(1024, i)).toFixed(2));
            return `${value}${sizes[i]}`;
        },
        getK2Gb(bs) {
            bs = bs / 1024 / 1024 / 1024;
            if (bs >= 1) {
                return Math.ceil(bs.toFixed(2)) + 'GB';
            } else {
                bs = bs * 1024;
                return Math.ceil(bs.toFixed(2)) + 'MB';
            }
        },
        // initializeTippyPopups 方法已迁移到 main.js
        generateUniqueTags() {
            const tags = new Set();
            if (this.servers) {
                this.servers.forEach(server => {
                    if (server.Tag && server.Tag.trim() !== '') {
                        tags.add(server.Tag.trim());
                    }
                });
            }
            this.uniqueTags = Array.from(tags).sort();
        },
        handleTabClick(tag, event) {
            this.activeTag = tag;
            this.$nextTick(() => {
                const tabEl = event.currentTarget;
                const tabsContainer = this.$refs.tabsContainer;
                if (tabEl && tabsContainer && tabsContainer.contains(tabEl)) {
                    if (tabsContainer.scrollWidth > tabsContainer.clientWidth) {
                        tabEl.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
                    }
                }

                // 分组切换后重新初始化 Tippy.js 弹窗
                // 等待 DOM 更新完成后再初始化
                setTimeout(() => {
                    if (window.TippyPopups && window.TippyPopups.initGlobal) {
                        window.TippyPopups.initGlobal();
                    }
                }, 100);
            });
        },
        updateSliderPosition() {
            const slider = this.$refs.tabSlider;
            if (!slider) return;

            let activeTabElement = null;
            if (this.activeTag === '') {
                activeTabElement = this.$refs.allTab;
            } else if (this.activeTag === 'online') {
                activeTabElement = this.$refs.onlineTab;
            } else if (this.activeTag === 'offline') {
                activeTabElement = this.$refs.offlineTab;
            } else {
                const reversedTags = this.uniqueTags.slice().reverse();
                const activeIndexInReversed = reversedTags.indexOf(this.activeTag);
                if (activeIndexInReversed !== -1 && this.$refs['tagTab' + activeIndexInReversed]) {
                    activeTabElement = this.$refs['tagTab' + activeIndexInReversed];
                    if (Array.isArray(activeTabElement)) {
                        activeTabElement = activeTabElement[0];
                    }
                }
            }

            if (!activeTabElement && this.$refs.allTab) {
                activeTabElement = this.$refs.allTab;
            }

            if (activeTabElement && this.$refs.tabsContainer) {
                const containerRect = this.$refs.tabsContainer.getBoundingClientRect();
                const tabRect = activeTabElement.getBoundingClientRect();
                const newLeft = tabRect.left - containerRect.left + this.$refs.tabsContainer.scrollLeft;
                const newWidth = tabRect.width;
                slider.style.left = `${newLeft}px`;
                slider.style.width = `${newWidth}px`;
            } else {
                slider.style.width = '0px';
            }
        },
        updateServerLiveStatus(wsData) {
            if (!wsData || !this.servers) return;

            // 优先使用服务器提供的时间戳，如果没有则使用本地时间
            const nowMillisFromWS = wsData.now || Date.now();

            // 如果没有服务器时间戳，记录一次警告（避免刷屏）
            if (!wsData.now && !this._warnedAboutMissingTimestamp) {
                console.warn('WebSocket data missing server timestamp, using local time');
                this._warnedAboutMissingTimestamp = true;
            }
            let hasUpdates = false;

            // 创建服务器ID到数据的映射，提高查找效率
            const serverMap = new Map();
            if (wsData.servers) {
                wsData.servers.forEach(server => {
                    serverMap.set(server.ID, server);
                });
            }

            this.servers.forEach(serverItem => {
                if (!serverItem.Host) {
                    if (serverItem.live !== false) {
                        serverItem.live = false;
                        hasUpdates = true;
                    }
                    return;
                }

                const wsServer = serverMap.get(serverItem.ID);
                if (wsServer) {
                    // 更新服务器状态
                    if (wsServer.State) {
                        const oldState = serverItem.State;
                        serverItem.State = {
                            ...oldState,
                            ...wsServer.State
                        };
                        hasUpdates = true;
                    }

                    // 更新最后活动时间
                    if (wsServer.LastActive) {
                        serverItem.LastActive = wsServer.LastActive;
                    }
                }

                // 计算在线状态
                const lastActiveTimestampMs = new Date(serverItem.LastActive).getTime();
                const diffMs = nowMillisFromWS - lastActiveTimestampMs;

                // 调整超时阈值：使用120秒（2分钟）匹配后端设置
                // 后端在singleton.go中设置为2分钟（line 896）
                // 添加10秒容错时间，处理时间不同步问题
                const offlineThreshold = 130000; // 2分钟 + 10秒容错

                // 状态变化检查
                if (serverItem.live === true && diffMs > offlineThreshold) {
                    // Server may go offline
                }

                const newLiveStatus = !isNaN(lastActiveTimestampMs) && diffMs < offlineThreshold && diffMs > -10000; // 也要检查未来时间

                // 改进状态稳定性检查
                if (serverItem.live !== newLiveStatus) {
                    // 从在线变为离线需要确认
                    if (serverItem.live === true && newLiveStatus === false) {
                        if (!serverItem._offlineConfirmCount) {
                            serverItem._offlineConfirmCount = 1;
                        } else if (serverItem._offlineConfirmCount < 2) { // 只需要连续2次确认
                            serverItem._offlineConfirmCount++;
                        } else {
                            // 连续3次确认离线才更新状态
                            serverItem.live = false;
                            serverItem._offlineConfirmCount = 0;
                            hasUpdates = true;
                        }
                    } else if (serverItem.live === false && newLiveStatus === true) {
                        // 从离线恢复到在线，立即更新
                        serverItem.live = true;
                        serverItem._offlineConfirmCount = 0;
                        hasUpdates = true;
                    }
                } else {
                    // 状态没有变化，重置确认计数
                    serverItem._offlineConfirmCount = 0;
                }
            });

            // 只有在有实际更新时才强制更新视图
            if (hasUpdates) {
                // 立即更新，不使用防抖（防抖可能导致状态显示延迟）
                this.$forceUpdate();

                // 更新当前显示的popup内容
                this.$nextTick(() => {
                    if (window.TippyPopups && window.TippyPopups.updateContent) {
                        window.TippyPopups.updateContent();
                    }
                });
            }
        },
        getTrafficProgressClass(serverId) {
            const trafficData = this.getServerTrafficData(serverId);
            if (!trafficData) {
                return 'ui progress offline';
            }

            const percent = trafficData.percent || 0;
            let classObject = { ui: true, progress: true };

            if (percent < 60) {
                classObject.fine = true;
            } else if (percent < 90) {
                classObject.warning = true;
            } else {
                classObject.error = true;
            }

            return Object.keys(classObject).join(' ');
        },
        getTrafficProgressStyle(serverId) {
            const trafficData = this.getServerTrafficData(serverId);
            if (!trafficData) {
                return {
                    'transition-duration': '300ms',
                    'width': '0%'
                };
            }

            const percent = trafficData.percent || 0;
            let bgColor = 'rgb(76,175,80)';

            if (percent >= 90) {
                bgColor = '#f44336';
            } else if (percent >= 60) {
                bgColor = '#ff9800';
            }

            return {
                'transition-duration': '300ms',
                'width': percent + '%',
                'background-color': bgColor
            };
        },
        getTrafficDisplay(serverId) {
            const trafficData = this.getServerTrafficData(serverId);
            if (!trafficData) {
                return '0%';
            }

            const percent = trafficData.percent || 0;
            return percent.toFixed(2) + '%';
        },
        getTrafficTooltip(serverId) {
            const trafficData = this.getServerTrafficData(serverId);
            if (!trafficData) {
                return '无数据';
            }

            const used = trafficData.used || '0B';
            const max = trafficData.max || '0B';
            return `${used} / ${max}`;
        },
        updateTrafficData() {
            if (!window.serverTrafficData) {
                return;
            }

            let hasUpdates = false;
            const trafficData = window.serverTrafficData;

            this.servers.forEach(server => {
                const trafficInfo = trafficData[server.ID];
                if (trafficInfo) {
                    const oldTraffic = server.traffic;
                    const newTraffic = {
                        used: trafficInfo.used,
                        total: trafficInfo.max,
                        percent: trafficInfo.percent,
                        lastUpdate: trafficInfo.lastUpdate
                    };

                    // 检查是否有实际更新，增加更详细的比较
                    if (!oldTraffic ||
                        oldTraffic.used !== newTraffic.used ||
                        oldTraffic.total !== newTraffic.total ||
                        Math.abs(oldTraffic.percent - newTraffic.percent) > 0.01) { // 百分比变化超过0.01%才更新
                        server.traffic = newTraffic;
                        hasUpdates = true;
                    }
                }
            });

            if (hasUpdates) {
                this.$forceUpdate();

                // 更新当前显示的popup内容
                this.$nextTick(() => {
                    if (window.TippyPopups && window.TippyPopups.updateContent) {
                        window.TippyPopups.updateContent();
                    }
                });
            }
        },
        hasTemperature(temperatureList, sensorList) {
            if (!temperatureList || !Array.isArray(temperatureList) || temperatureList.length === 0) {
                return false;
            }
            return temperatureList.some(item => item.Temperature !== 0);
        },
        getTemperature(temperatureList, sensorList) {
            if (!temperatureList || !Array.isArray(temperatureList) || temperatureList.length === 0) {
                return '';
            }

            const lowerCaseSensorList = sensorList.map(sensor => sensor.toLowerCase());
            const filtered = temperatureList.filter(item =>
                item.Temperature !== 0 &&
                item.Name &&
                lowerCaseSensorList.includes(item.Name.toLowerCase())
            );

            if (filtered.length > 0) {
                const maxTemp = filtered.reduce((max, current) =>
                    current.Temperature > max ? current.Temperature : max,
                    filtered[0].Temperature
                );
                return maxTemp.toFixed(1);
            }

            const nonZeroTemps = temperatureList.filter(item => item.Temperature !== 0);
            if (nonZeroTemps.length > 0) {
                const maxTemp = nonZeroTemps.reduce((max, current) =>
                    current.Temperature > max ? current.Temperature : max,
                    nonZeroTemps[0].Temperature
                );
                return maxTemp.toFixed(1);
            }

            return '';
        },
        getServerCountForTag(tag) {
            if (!this.servers || !Array.isArray(this.servers)) {
                return 0;
            }

            const displayableServers = this.servers.filter(server => server.Host);

            if (tag === '') {
                return displayableServers.length;
            } else if (tag === 'online') {
                return displayableServers.filter(server => server.live === true).length;
            } else if (tag === 'offline') {
                return displayableServers.filter(server => server.live === false).length;
            }

            return displayableServers.filter(server => server.Tag === tag).length;
        }
    },
    watch: {
        activeTag() {
            this.$nextTick(() => {
                this.updateSliderPosition();
            });
        },
        uniqueTags() {
            this.$nextTick(() => {
                this.updateSliderPosition();
            });
        },
        servers() {
            this.generateUniqueTags();
            this.$nextTick(() => {
                this.updateSliderPosition();
            });
        }
    },
    beforeDestroy() {
        if (window.trafficManager) {
            window.trafficManager.unsubscribe(this.updateTrafficData);
        }
    }
});

    // 全局WebSocket状态管理
    const wsManager = {
        ws: null,
        lastPing: Date.now(),
        reconnectTimer: null,
        healthCheckTimer: null,
        reconnectAttempts: 0,
        maxReconnectAttempts: 10,
        isReconnecting: false,
        pingInterval: null,

        // 健康检查
        startHealthCheck() {
            this.stopHealthCheck();
            this.healthCheckTimer = setInterval(() => {
                if (this.ws && this.ws.readyState === WebSocket.OPEN) {
                    // 检查上次接收消息的时间
                    const timeSinceLastMessage = Date.now() - this.lastPing;
                    if (timeSinceLastMessage > 35000) { // 35秒没有收到消息（留5秒余量）
                        console.warn('WebSocket health check failed, reconnecting...');
                        this.reconnect();
                    } else if (timeSinceLastMessage > 20000) {
                        // 20秒没有收到消息，发送一个ping
                        try {
                            this.ws.send(JSON.stringify({ type: 'ping' }));
                        } catch (e) {
                            console.warn('Failed to send ping:', e);
                        }
                    }
                }
            }, 15000); // 每15秒检查一次
        },

        stopHealthCheck() {
            if (this.healthCheckTimer) {
                clearInterval(this.healthCheckTimer);
                this.healthCheckTimer = null;
            }
            if (this.pingInterval) {
                clearInterval(this.pingInterval);
                this.pingInterval = null;
            }
        },

        reconnect() {
            if (this.isReconnecting) {
                return; // 避免重复重连
            }

            this.isReconnecting = true;
            this.close();
            this.reconnectAttempts++;

            if (this.reconnectAttempts > this.maxReconnectAttempts) {
                console.error('Max reconnect attempts reached');
                this.isReconnecting = false;
                // 显示错误提示，但不立即刷新页面
                this.showConnectionError();
                return;
            }

            // 使用指数退避算法，但限制最大延迟为30秒
            const delay = Math.min(1000 * Math.pow(1.5, this.reconnectAttempts - 1), 30000);
            console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);

            this.reconnectTimer = setTimeout(() => {
                this.isReconnecting = false;
                initWebSocket();
            }, delay);
        },

        close() {
            this.stopHealthCheck();
            if (this.reconnectTimer) {
                clearTimeout(this.reconnectTimer);
                this.reconnectTimer = null;
            }
            if (this.ws) {
                try {
                    this.ws.close(1000, 'Normal closure');
                } catch (e) {
                    console.warn('Error closing WebSocket:', e);
                }
                this.ws = null;
            }
        },

        reset() {
            this.reconnectAttempts = 0;
            this.lastPing = Date.now();
            this.isReconnecting = false;
        }

    };

    // 使Vue实例全局可用
    window.statusCards = statusCards;

    // Tippy.js 弹窗已迁移到 main.js

    // 初始化WebSocket连接
    function initWebSocket() {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${protocol}//${window.location.host}/ws`;

        // 关闭旧连接
        if (wsManager.ws) {
            wsManager.close();
        }

        const ws = new WebSocket(wsUrl);
        wsManager.ws = ws;

        ws.onopen = function () {
            console.log('WebSocket connected');
            wsManager.reset();
            wsManager.startHealthCheck();

            // 显示连接成功提示（如果是重连）
            if (wsManager.reconnectAttempts > 0) {
                const existingError = document.querySelector('.websocket-error-msg');
                if (existingError) {
                    existingError.remove();
                }
                const msg = document.createElement('div');
                msg.className = 'ui positive message';
                msg.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 400px;';
                msg.innerHTML = `
                <i class="close icon" onclick="this.parentElement.remove()"></i>
                <div class="header">连接已恢复</div>
                <p>与服务器的连接已恢复，数据将实时更新。</p>
            `;
                document.body.appendChild(msg);
                setTimeout(() => msg.remove(), 5000);
            }

            try {
                ws.send(JSON.stringify({ type: 'ping' }));
            } catch (e) {
                console.warn('WebSocket ping failed:', e);
            }
        };

        ws.onmessage = function (event) {
            wsManager.lastPing = Date.now();
            wsManager.reconnectAttempts = 0; // 重置重连次数

            try {
                const data = JSON.parse(event.data);

                // 处理服务端pong响应
                if (data.type === 'pong') {
                    return;
                }

                // 处理服务器状态更新
                if (data.servers && Array.isArray(data.servers)) {
                    if (window.statusCards) {
                        window.statusCards.updateServerLiveStatus(data);
                    }
                }

                // 处理流量数据更新 - 流量数据可能单独发送或与服务器状态一起发送
                if (data.trafficData && Array.isArray(data.trafficData)) {
                    window.serverTrafficRawData = data.trafficData;
                    if (window.trafficManager) {
                        window.trafficManager.processTrafficData(data.trafficData);
                    } else {
                        window.extractTrafficData();
                    }
                }
            } catch (e) {
                console.warn('WebSocket message parsing failed:', e);
            }
        };

        ws.onerror = function (error) {
            console.warn('WebSocket error:', error);
            // 显示错误提示
            if (!document.querySelector('.websocket-error-msg')) {
                const msg = document.createElement('div');
                msg.className = 'ui warning message';
                msg.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 400px;';
                msg.innerHTML = `
                <i class="close icon" onclick="this.parentElement.remove()"></i>
                <div class="header">连接出现问题</div>
                <p>与服务器的连接出现问题，正在尝试重新连接...</p>
            `;
                document.body.appendChild(msg);
                setTimeout(() => msg.remove(), 10000);
            }
        };

        ws.onclose = function (event) {
            console.log('WebSocket closed:', event.code, event.reason);
            wsManager.ws = null;
            wsManager.stopHealthCheck();

            // 只有非正常关闭才重连
            if (event.code !== 1000 && event.code !== 1001) {
                wsManager.reconnect();
            }
        };

        return ws;
    }





    $(document).ready(function () {
        // 初始化 Tippy.js 弹窗（使用 main.js 中的函数）
        if (window.TippyPopups && window.TippyPopups.init) {
            window.TippyPopups.init();
        }

        // 初始化WebSocket连接（仅在首页）
        if (window.location.pathname === '/' || window.location.pathname === '/home') {
            window.ws = initWebSocket();

            // 添加页面可见性变化监听
            document.addEventListener('visibilitychange', function () {
                if (document.visibilityState === 'visible') {
                    // 页面变为可见时，检查WebSocket连接状态
                    if (!wsManager.ws || wsManager.ws.readyState !== WebSocket.OPEN) {
                        console.log('Page became visible, checking WebSocket connection...');
                        // 延迟1秒后重连，避免频繁切换标签导致的问题
                        setTimeout(() => {
                            if (!wsManager.ws || wsManager.ws.readyState !== WebSocket.OPEN) {
                                wsManager.reconnect();
                            }
                        }, 1000);
                    } else {
                        // 连接正常，重启健康检查
                        wsManager.startHealthCheck();
                    }
                } else {
                    // 页面隐藏时，停止健康检查但不断开连接
                    wsManager.stopHealthCheck();
                }
            });

            // 监听网络状态变化
            window.addEventListener('online', function () {
                console.log('Network connection restored');
                if (!wsManager.ws || wsManager.ws.readyState !== WebSocket.OPEN) {
                    wsManager.reconnect();
                }
            });

            window.addEventListener('offline', function () {
                console.log('Network connection lost');
                wsManager.showConnectionError();
            });

            // 页面卸载时清理
            window.addEventListener('beforeunload', function () {
                wsManager.close();
            });
        }

        $('.ui.accordion').accordion({
            exclusive: false,
            silent: true,
            performance: true,
            selector: {
                trigger: '.title'
            },
            duration: 200,
            easing: 'easeOutQuad'
        });

        $(document).off('touchstart.accordion touchmove.accordion');
        $(document).on('touchstart.accordion', '.ui.accordion .title', function (e) {
            // 被动处理，不阻止默认行为
        });
    });
</script>
{{end}}